import logging
import os, pdb
import time, json
import hashlib

from django.conf import settings
from django.core.files.base import ContentFile
from django.core.files.storage import default_storage
from django.http import JsonResponse

from conf.sysConfig import config
from software.utils import fileStore, createLog
from software.models import Software, SoftwareType, SoftwareVersion, SoftwareData
from storehouse.models import Storehouse
from user import dataCheck as da
from user.dataCheck import DataCheck
from user.dataCheck import randomNumber
from user.models import Company, FileStore
from software.views.view_download import download
from order.views.createOrder import random_str
from announcement.views.views_anno import createAnnouncement
from question.models import SoftwareQuestion, QuestionHandle
import xlrd
from software.utils.duan_xml import unzip_Sim_XmlFile
from software.models import DuanInfo
from django.db import transaction
from pprint import pprint

datacheck = DataCheck()
tmpDir = os.path.join(config["dataDir"], config["tmpDir"])
chunkDir = os.path.join(config["dataDir"], config["chunk"])
fileDir = os.path.join(config["dataDir"], config["file"])
coverDir = os.path.join(config["dataDir"], config["cover"])
logoDir = os.path.join(config["dataDir"], config["logo"])
materialDir = os.path.join(config["dataDir"], config["material"])
verificationDir = os.path.join(config["dataDir"], config["verification"])
QAFileDir = os.path.join(config["dataDir"], config["questionAnswer"])
logger_request = logging.getLogger("django.request")
logger_test = logging.getLogger("userlog")


@transaction.atomic()
def uploadSoft(request, *args, **kwargs):
    '''
        url:'/develop/soft/upload',
            method:'post',
            inputData:{
                token:data.token,//
                softname:data.softname,//软件名称
                description:data.description,//软件描述
                version:data.version,
                upcompany:data.upcompany,//上传单位
                category:data.category,//软件分类
                logo:data.logo,//软件logo
                cover:data.cover,//软件封面
                verification:data.verification,//查杀证明
                software:data.software,//软件流文件
                materail:data.materail,//资料流文件 [{'id'：1, 'dataName': ''}, {'id': 2, 'dataName': ''}] json
            }

        :param USERTYPE = (
                (1, u'开发人员'),
                (2, u'仓库管理人员'),
                (3, u'使用人员'),
                )
    '''
    form = request.checkForm
    requestParam = form.cleaned_data
    logger_request.info(requestParam)
    user = datacheck.getUser(requestParam["token"])

    # uploadUser userType
    userType = user.userType
    s1 = transaction.savepoint()
    # version file
    fileList = []
    try:
        fileIdList = json.loads(requestParam['fileId'])
        fileList = [FileStore.objects.filter(pk=i).first() for i in fileIdList]
        logger_test.info(fileList)
    except:
        data = {
            "code": 1,
            "msg": "FileID Error",
        }
        logger_request.info(data)
        return JsonResponse(data)

    if requestParam['softwareId'] != '':
        String = da.randomNumber(30)
        software = Software.objects.filter(pk=requestParam['softwareId'])
        # get softwareVersion param and create softwareVersion
        softwareVersionList = SoftwareVersion.objects.filter(software=software[0], version=requestParam['version'])
        softwareItem = software[0]
        # num = 0
        # for softwareCurrent in softwareVersionList:
        #     version = softwareCurrent.version
        #     if requestParam['version'] == version:
        #         num += 1
        #     else:
        #         pass

        if not softwareVersionList.exists():  # 版本号不同，更新2.0
            company = Company.objects.filter(pk=requestParam['company'])
            storehouse = Storehouse.objects.filter(pk=requestParam['storehouse'])
            softwareType = SoftwareType.objects.filter(pk=requestParam['softwareType'])
            logo = FileStore.objects.filter(pk=requestParam['logo'])
            cover = FileStore.objects.filter(pk=requestParam['cover'])
            verification = FileStore.objects.filter(pk=requestParam['verification'])
            softwareVersion = SoftwareVersion.objects.create(
                user=user,
                store=storehouse[0],
                softwareType=softwareType[0],
                softwareName=requestParam['softwareName'],
                designUnit=company[0],
                cover=cover[0],
                logo=logo[0],
                software=softwareItem,
                softwareVersionId=String,
                verification=verification[0],
                cost=requestParam['cost'],
                version=requestParam['version'],
                updateDetails=requestParam['softwareDetails'],
                currentVersionDesc=requestParam['currentVersionDesc'],
                isSeg=requestParam['isSeg']
            )
            for item in fileList:
                softwareVersion.file.add(item)
            softwareVersion.save()
            # dataFunction dataVersion
            if requestParam['material'] != '':
                for materialItem in requestParam['material']:
                    material = FileStore.objects.filter(pk=materialItem['id'])
                    softwareData = SoftwareData.objects.create(
                        dataName=material[0].fileName,
                        # updateDetails=materialItem['updateDetails'],
                        file=material[0]
                    )
                    softwareData.softwareVersion.add(softwareVersion)
                    softwareData.save()
            if requestParam['questionAnswer'] != '':
                for qaItem in requestParam['questionAnswer']:
                    qafile = FileStore.objects.filter(pk=qaItem['id'])
                    qafileItem = qafile[0]
                    softwareVersion.qaFile.add(qafileItem)
                    softwareVersion.save()

            option = "用户 " + user.username + "更新了软件 [" + softwareVersion.softwareName + "] 版本:" + softwareVersion.version
            createLog.createLog(option, softwareVersion.id, user.id)
            data = {
                "code": 0,
                "msg": "success",
            }
        else:  # 将1.0重新更正上传
            softwareVersionList = SoftwareVersion.objects.filter(version=requestParam['version'], software=softwareItem)
            softwareVersion = softwareVersionList[0]

            softwareType = SoftwareType.objects.filter(pk=requestParam['softwareType'])
            verification = FileStore.objects.filter(pk=requestParam['verification'])
            cover = FileStore.objects.filter(pk=requestParam['cover'])
            logo = FileStore.objects.filter(pk=requestParam['logo'])
            company = Company.objects.filter(pk=requestParam['company'])
            softwareVersion.softwareType = softwareType[0]
            softwareVersion.softwareName = requestParam['softwareName']
            softwareVersion.designUnit = company[0]
            softwareVersion.logo = logo[0]
            softwareVersion.cover = cover[0]
            softwareVersion.verification = verification[0]

            softwareVersion.save()

            softwareItem.softwareId = String
            softwareItem.softwareDetails = requestParam['softwareDetails']
            softwareItem.save()

            softwareVersion.updateDetails = requestParam['softwareDetails']
            softwareVersion.cost = requestParam['cost']
            softwareVersion.examineState = 0
            softwareVersion.isExamine = False
            softwareVersion.save()
            for item in fileList:
                softwareVersion.file.add(item)
            softwareVersion.save()
            if requestParam['material'] != '':
                for materialItem in requestParam['material']:
                    material = FileStore.objects.filter(pk=materialItem['id'])
                    materialCurrent = SoftwareData.objects.filter(file=material[0])
                    if materialCurrent.exists():
                        pass
                    else:
                        softwareData = SoftwareData.objects.create(
                            dataName=material[0].fileName,
                            # updateDetails=materialItem['updateDetails'],
                            file=material[0]
                        )
                        # 多对多添加数据
                        softwareData.softwareVersion.add(softwareVersion)
                        softwareData.save()
            if requestParam['questionAnswer'] != '':
                for qaItem in requestParam['questionAnswer']:

                    for QAFileItem in softwareVersion.qaFile.all():
                        softwareVersion.qaFile.remove(QAFileItem)

                    qafile1 = FileStore.objects.filter(pk=qaItem['id'])
                    qafileItem = qafile1[0]
                    softwareVersion.qaFile.add(qafileItem)
                    softwareVersion.save()
            data = {
                "code": 0,
                "msg": "success",
            }
    elif requestParam['softwareId'] == '':
        if userType in ['1', '2', '3']:
            # get software param and create software
            String = da.randomNumber(30)
            company = Company.objects.filter(pk=requestParam['company'])
            softwareType = SoftwareType.objects.filter(pk=requestParam['softwareType'])
            store = Storehouse.objects.filter(pk=requestParam['storehouse'])
            if requestParam['logo'] == '' or requestParam['cover'] == '' or requestParam['verification'] == '':
                data = {
                    "code": 1,
                    "msg": "logo cover verification empty",
                }
                transaction.savepoint_rollback(s1)
                logger_request.info(data)
                return JsonResponse(data)
            logo = FileStore.objects.filter(pk=requestParam['logo'])
            cover = FileStore.objects.filter(pk=requestParam['cover'])
            verification = FileStore.objects.filter(pk=requestParam['verification'])
            software = Software.objects.create(
                user=user,
                softwareId=String,
                softwareDetails=requestParam['softwareDetails'],
            )
            # get softwareVersion param and create softwareVersion
            softwareVersion = SoftwareVersion.objects.create(
                user=user,
                store=store[0],
                softwareType=softwareType[0],
                softwareName=requestParam['softwareName'],
                designUnit=company[0],
                cover=cover[0],
                logo=logo[0],
                software=software,
                softwareVersionId=String,
                verification=verification[0],
                cost=requestParam['cost'],
                version=requestParam['version'],
                updateDetails=requestParam['softwareDetails'],
                currentVersionDesc=requestParam['currentVersionDesc'],
                isSeg=requestParam['isSeg']
            )
            for item in fileList:
                softwareVersion.file.add(item)
                softwareVersion.save()
            # dataFunction dataVersion
            if requestParam['material'] != '':
                for materialItem in requestParam['material']:
                    material = FileStore.objects.filter(pk=materialItem['id'])
                    softwareData = SoftwareData.objects.create(
                        dataName=material[0].fileName,
                        # updateDetails=materialItem['updateDetails'],
                        file=material[0]
                    )
                    # 多对多添加数据
                    softwareData.softwareVersion.add(softwareVersion)
                    softwareData.save()
            # pdb.set_trace()
            if requestParam['questionAnswer'] != '':
                for qaItem in requestParam['questionAnswer']:
                    qafile = FileStore.objects.filter(pk=qaItem['id'])
                    qafileItem = qafile[0]
                    softwareVersion.qaFile.add(qafileItem)
                    softwareVersion.save()

            data = {
                "code": 0,
                "msg": "success",
            }
            createAnnouncement(
                userId=user.id,
                type='software',
                num='5',
                userType='2',
                softwareVersionId=softwareVersion.id,
            )
            option = "用户 " + user.username + "上传了新软件 [" + softwareVersion.softwareName + "] 版本:" + softwareVersion.version
            createLog.createLog(option, softwareVersion.id, user.id)
        else:
            data = {
                "code": 1,
                "msg": "NonePermission",
            }
            transaction.savepoint_rollback(s1)
            logger_request.info(data)
            return JsonResponse(data)
    else:
        data = {
            "code": 1,
            "msg": "ParamError",
        }
        transaction.savepoint_rollback(s1)
        logger_request.info(data)
        return JsonResponse(data)

    # duan xml
    logger_test.info("isSeg:" + requestParam['isSeg'])
    logger_request.info("fileList:" + requestParam['isSeg'])
    if requestParam['isSeg'] == '1':
        for i in fileList:
            duanInfo = unzip_Sim_XmlFile(path=i.filePath, fileName='SegInfo.xml')
            logger_test.info(duanInfo)
            logger_test.info(duanInfo['VERSION'])
            if duanInfo['VERSION'] == '':
                try:
                    raise Exception("duan version none")
                except:
                    data = {
                        "code": 300,
                        "msg": "duan version none",
                    }
                    transaction.savepoint_rollback(s1)
                    logger_request.info(data)
                    return JsonResponse(data)
            version = '.'.join(duanInfo['VERSION'].split('.')[0:-1])
            logger_test.info(version)
            logger_test.info(softwareVersion.version)
            if version != softwareVersion.version:
                try:
                    raise Exception("duan version error")
                except:
                    data = {
                        "code": 302,
                        "msg": "duan version error",
                    }
                    transaction.savepoint_rollback(s1)
                    logger_request.info(data)
                    return JsonResponse(data)
            logger_test.info(duanInfo["VERSION"])
            logger_test.info(duanInfo["CPU"])
            duanList = DuanInfo.objects.filter(duanVersion__icontains=duanInfo["VERSION"],
                                               cpuType=duanInfo["CPU"],
                                               duanPrefix=duanInfo["PREFIX"])
            if requestParam['softwareId'] != '':
                if duanList.exists():
                    duan = duanList[0]
                    duan.file = i
                    duan.save()
                    duan.type = duanInfo["TYPE"]
                    duan.duanName = duanInfo["NAME"]
                    duan.duanDesc = duanInfo["DESCRIPT"]
                    duan.duanPrefix = duanInfo["PREFIX"]
                    duan.duanVersion = duanInfo["VERSION"]
                    duan.cpuType = duanInfo["CPU"]
                    duan.developUnit = duanInfo["PRODUCER"]
                    duan.duanType = duanInfo["APPTYPE"]
                    duan.realteId = json.dumps(duanInfo["HostRequires"])
                    duan.save()
                    logger_request.info(duanInfo)
                else:
                    duans = DuanInfo.objects.filter(softwareVersion=softwareVersion, isLatest=1)
                    if duans.exists():
                        for item in duans:
                            item.isLatest = 0
                            item.save()
                    DuanInfo.objects.create(
                        softwareVersion=softwareVersion,
                        file=i,
                        type=duanInfo["TYPE"],
                        duanName=duanInfo["NAME"],
                        duanDesc=duanInfo["DESCRIPT"],
                        duanPrefix=duanInfo["PREFIX"],
                        duanVersion=duanInfo["VERSION"],
                        cpuType=duanInfo["CPU"],
                        developUnit=duanInfo["PRODUCER"],
                        duanType=duanInfo["APPTYPE"],
                        isLatest=True,
                        realteId=json.dumps(duanInfo["HostRequires"])
                    )
            else:
                DuanInfo.objects.create(
                    softwareVersion=softwareVersion,
                    file=i,
                    type=duanInfo["TYPE"],
                    duanName=duanInfo["NAME"],
                    duanDesc=duanInfo["DESCRIPT"],
                    duanPrefix=duanInfo["PREFIX"],
                    duanVersion=duanInfo["VERSION"],
                    cpuType=duanInfo["CPU"],
                    developUnit=duanInfo["PRODUCER"],
                    duanType=duanInfo["APPTYPE"],
                    isLatest=True,
                    realteId=json.dumps(duanInfo["HostRequires"])
                )
    else:
        logger_test.info('exe')
    transaction.savepoint_commit(s1)
    logger_request.info(data)
    return JsonResponse(data)


# 上传文件
def uploadfiles(request, *args, **kwargs):
    """
        url    : /develop/soft/uploadFile
        method : POST

        :param request:

        :return:

    """
    # print(request.FILES.get('audio', False))
    form = request.checkForm
    requestParam = form.cleaned_data
    logger_request.info(requestParam)
    user = datacheck.getUser(requestParam["token"])
    # pdb.set_trace()
    # todo
    if request.FILES.get('file', False):
        audio = request.FILES.get('file')
        local_time = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
        name = audio.name
        if requestParam['fileType'] == 'file':
            dir = fileDir
            fileType = 2
        elif requestParam['fileType'] == 'cover':
            dir = coverDir
            fileType = 4
        elif requestParam['fileType'] == 'logo':
            dir = logoDir
            fileType = 3
        elif requestParam['fileType'] == 'material':
            dir = materialDir
            fileType = 0
        elif requestParam['fileType'] == 'verification':
            dir = verificationDir
            fileType = 1
        elif requestParam['fileType'] == 'QAFile':
            dir = QAFileDir
            fileType = 6
        else:
            dir = ''
            fileType = -1
        if requestParam['fileType'] != 'file':
            fileSuffix = name.split('.')[1]
            strSuffix = local_time + random_str(8) + '.' + fileSuffix
            address = os.path.join(dir, strSuffix)
            fileObj = open(address, 'wb')
            for line in audio.chunks():
                fileObj.write(line)
            fileObj.close()
            # path = default_storage.save(address, ContentFile(audio.read()))
            fileId = fileStore.saveToDatabase(name, user, address, fileType=fileType, uniqueFile=getLocalToken())
            data = {
                'code': 0,
                'msg': 'success',
                'fileId': fileId,
                'url': download(name, requestParam['fileType'], address)[1],
                'name': name,
            }
        else:
            data = {
                'code': 1,
                'msg': 'fileTypeError',
                'fileId': "",
                'url': "",
                'name': "",
            }
    else:
        # 文件名称
        # local_time = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
        # name = local_time + random_str(8) + str(user.id) + '.txt'
        # address = os.path.join(tmpDir, name)
        # fileId = fileStore.saveToDatabase(name, user, address, fileType=0)
        data = {
            'code': 1,
            'msg': 'File None1',
            'fileId': '',
        }
    logger_request.info(data)
    return JsonResponse(data)


# 断点续传
def index(request, *args, **kwargs):
    pass
    data = {
        'code': 0,
        'msg': 'success',
    }
    logger_request.info(data)
    return JsonResponse(data)


def checkChunk(request, *args, **kwargs):
    # post请求
    if request.method == 'POST':
        # 获得上传文件块的大小,如果为0，就告诉他不要上传了
        chunkSize = request.POST.get("chunkSize")
        if chunkSize == '0':
            data = {
                'code': 1,
                'msg': 'success',
                'ifExist': True
            }
            logger_request.info(data)
            return JsonResponse(data)
        # 如果文件块大小不为0 ，那么就上传，需要拼接一个临时文件
        file_name = request.POST.get('fileMd5') + request.POST.get('chunk')

        # 如果说这个文件不在已经上传的目录，就可以上传，已经存在了就不需要上传。
        if file_name not in get_deep_data():
            data = {
                'code': 1,
                'msg': 'success',
                'ifExist': True
            }
            logger_request.info(data)
            return JsonResponse(data)
        data = {
            'code': 1,
            'msg': 'success',
            'ifExist': True
        }
        logger_request.info(data)
        return JsonResponse(data)

    data = {
        'code': 0,
        'msg': 'success',
    }
    logger_request.info(data)
    return JsonResponse(data)


def mergeChunks(request, *args, **kwargs):  ##拼接成一个文件
    if request.method == 'POST':
        # 获取需要给文件命名的名称
        fileName = request.POST.get("fileName")
        # 该图片上传使用的md5码值
        md5 = request.POST.get("fileMd5")
        id = request.POST.get("fileId")
        # 分片的序号
        chunk = 0
        # 完成的文件的地址为
        path = os.path.join('static', 'upload', fileName)
        with open(path, 'wb') as fp:
            while True:
                try:
                    filename = 'static/upload/{}-{}'.format(md5, chunk)
                    with open(filename, 'rb') as f:
                        fp.write(f.read())
                    # 当图片写入完成后，分片就没有意义了，删除
                    os.remove(filename)
                except:
                    break
                chunk += 1

        return JsonResponse({'upload': True, 'fileName': fileName, 'fileId': id})
    data = {
        'code': 0,
        'msg': 'success',
    }
    logger_request.info(data)
    return JsonResponse(data)


def uploadNew(request, *args, **kwargs):  # 保存到指定目录下
    if request.method == 'POST':
        md5 = request.POST.get("fileMd5")
        chunk_id = request.POST.get("chunk", "0")
        fileName = "%s-%s" % (md5, chunk_id)
        file = request.FILES.get("file")
        with open(os.path.join(tmpDir, 'chunk/') + fileName, 'wb') as f:
            for i in file.chunks():
                f.write(i)
        data = {
            'code': 0,
            'msg': 'success',
            'upload_part': True
        }
        logger_request.info(data)
        return JsonResponse(data)
    data = {
        'code': 0,
        'msg': 'success',
    }
    logger_request.info(data)
    return JsonResponse(data)


# 判断一个文件是否在一个目录下
def get_deep_data(path=tmpDir):
    dir = os.path.join(tmpDir, "chunk")
    if not os.path.exists(dir):
        os.makedirs(dir)
    result = []
    data = os.listdir(dir)
    for i in data:
        if os.path.isdir(i):
            get_deep_data(i)
        else:
            result.append(i)
    return result


# 新断点续传
def uploadChunk(request, *args, **kwargs):
    # post请求
    form = request.checkForm
    requestParam = form.cleaned_data
    logger_request.info(requestParam)
    user = datacheck.getUser(requestParam["token"])

    # pdb.set_trace()    
    if request.method == 'POST':
        # 获得上传文件块的大小,如果为0，就告诉他不要上传了
        # file1 = request.POST.get("file")
        # pdb.set_trace()
        # print(file1) 
        chunkSize = request.POST.get("currentChunkSize")
        if chunkSize == '0':
            data = {
                'code': 1,
                'msg': 'success',
                'fileId': '',
                'url': '',
                'name': '',
            }
            logger_request.info(data)
            return JsonResponse(data)

        fileName = requestParam["filename"]
        identifier = requestParam["identifier"]
        chunkNumber = requestParam["chunkNumber"]
        file = request.FILES.get("file")
        # pdb.set_trace()
        name = file.name
        fileSuffix = name.split('.')[-1]
        strSuffix = chunkNumber + '.' + fileSuffix

        if strSuffix not in get_chunk_data(identifier):
            dir = chunkDir

            # 每个分片保存
            # pdb.set_trace()            

            with open(os.path.join(dir, identifier, strSuffix), 'wb') as f:
                # for i in file.chunks():
                f.write(file.read())

            filedir = os.path.join(dir, identifier)
            # 最后合并成一个文件,判断分片数量与所传数量是否一致
            data1 = os.listdir(filedir)
            chunkNum = len(data1)

            if str(chunkNum) == requestParam["totalChunks"]:
                # 完成的文件的地址为
                chunk = 1
                dir2 = fileDir
                fileStrSuffix = identifier + '.' + fileSuffix
                path = os.path.join(dir2, fileStrSuffix)
                # pdb.set_trace()
                with open(path, 'wb') as fp:
                    while True:
                        try:
                            strSuffix1 = str(chunk) + '.' + fileSuffix
                            # filename = 'C:/360Downloads/ck/data/software/chunk/{}/{}'.format(identifier,strSuffix1)
                            filename = '/data/software/chunk/{}/{}'.format(identifier, strSuffix1)
                            # filename = 'data/software/chunk/{}'.format(strSuffix1)
                            with open(filename, 'rb') as f:
                                fp.write(f.read())
                            # 当图片写入完成后，分片就没有意义了，删除
                            os.remove(filename)
                        except:
                            break
                        chunk += 1
                        if chunk > chunkNum:
                            break

                fileId = fileStore.saveToDatabase(fileName, user, path, fileType=2, uniqueFile=getLocalToken())

                data = {
                    'code': 0,
                    'msg': 'success',
                    'fileId': fileId,
                    'url': download(fileName, requestParam['fileType'], path)[1],
                    'name': fileName,
                }
                logger_request.info(data)
                return JsonResponse(data)
            # data = {
            #     'code': 0,
            #     'msg': 'success',
            #     'fileId': '',
            #     'url': '',
            #     'name':'',
            # }
            # logger_request.info(data)
            # return JsonResponse(data)
        data = {
            'code': 0,
            'msg': 'success',
            'fileId': '',
            'url': '',
            'name': '',
        }
        logger_request.info(data)
        return JsonResponse(data)


def get_chunk_data(identifier):
    chunkDir1 = os.path.join(chunkDir, identifier)
    # print(chunkDir1)
    if not os.path.exists(chunkDir1):
        os.makedirs(chunkDir1)
    result = []
    # pdb.set_trace()
    data = os.listdir(chunkDir1)
    if len(data) != 0:
        for i in data:
            if os.path.isdir(i):
                get_chunk_data(i)
            else:
                result.append(i)
    return result


def getLocalToken():
    timeStamp = time.time()
    localTime = time.localtime(timeStamp)
    strTime = time.strftime("%Y%m%d%H", localTime)
    str = randomNumber(30)
    hl = hashlib.md5()
    hl.update(str.encode(encoding='utf-8'))
    return hl.hexdigest()[0:20]
